refer to: https://z3tt.github.io/OutlierConf2021/?s=09

loadedPackages <- c(
    "tidyverse",        ## data science package collection (incl. the ggplot2 package)
    "systemfonts",      ## use custom fonts (needs to be installed on your OS)
    "scico",            ## scico color paletters (http://www.fabiocrameri.ch/colourmaps.php) in R 
    "ggtext",           ## add improved text rendering to ggplot2
    "ggforce",          ## add missing functionality to ggplot2
    "ggdist",           ## add uncertainty visualization to ggplot2
    "magick",           ## load images to R
    "patchwork",        ## combine outputs from ggplot2
    "IRdisplay"         ## 'Jupyter' Display Machinery
)
invisible(lapply(loadedPackages, library, character.only=TRUE, verbose=FALSE, warn.conflicts=FALSE))
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
─ Attaching packages ───────────────────────────────────────────── tidyverse 1.3.1 ─
✓ ggplot2 3.3.3.9000     ✓ purrr   0.3.4     
✓ tibble  3.1.0          ✓ dplyr   1.0.5     
✓ tidyr   1.1.3          ✓ stringr 1.4.0     
✓ readr   1.4.0          ✓ forcats 0.5.1     
─ Conflicts ─────────────────────────────────────────────── tidyverse_conflicts() ─
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
Linking to ImageMagick 6.9.10.23
Enabled features: fontconfig, freetype, fftw, lcms, pango, webp, x11
Disabled features: cairo, ghostscript, heic, raw, rsvg
Using 36 threads
Registered S3 methods overwritten by 'htmltools':
  method               from         
  print.html           tools:rstudio
  print.shiny.tag      tools:rstudio
  print.shiny.tag.list tools:rstudio

Data


Data were collected and made available by Dr. Kristen Gorman and the Palmer Station, Antarctica LTER, a member of the Long Term Ecological Research Network.

penguins <- 
  readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2020/2020-07-28/penguins.csv') %>% 
  ## correct species name
  mutate(species = if_else(species == "Adelie", "Adélie", species)) %>% 
  ## remove missing observations
  filter(!is.na(bill_length_mm), !is.na(bill_depth_mm))

─ Column specification ──────────────────────────────────────────────────────
cols(
  species = col_character(),
  island = col_character(),
  bill_length_mm = col_double(),
  bill_depth_mm = col_double(),
  flipper_length_mm = col_double(),
  body_mass_g = col_double(),
  sex = col_character(),
  year = col_double()
)
penguins

A Basic ggplot

## simple plot: data + mappings + geometry
ggplot(penguins, aes(x = bill_length_mm, y = bill_depth_mm)) +
  geom_point(alpha = .6, size = 3.5) +
  theme(text = element_text(size = 20)) 

## change global theme settings (for all following plots)
theme_set(theme_minimal(base_size = 16, base_family = "Open Sans"))

## modify plot elements globally (for all following plots)
theme_update(
  axis.ticks = element_line(color = "grey92"),
  axis.ticks.length = unit(.5, "lines"),
  panel.grid.minor = element_blank(),
  legend.title = element_text(size = 12),
  legend.text = element_text(color = "grey30"),
  plot.title = element_text(size = 22, face = "bold"),
  plot.subtitle = element_text(size = 16, color = "grey30"),
  plot.caption = element_text(size = 14, margin = margin(t = 15))
)
ggplot(penguins, aes(x = bill_length_mm, y = bill_depth_mm)) +
  geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5) + 
  ## custom axes scaling
  scale_x_continuous(breaks = 3:6 * 10, limits = c(30, 60)) +
  scale_y_continuous(breaks = seq(12.5, 22.5, by = 2.5), limits = c(12.5, 22.5)) +
  ## custom colors
  scico::scale_color_scico(palette = "bamako", direction = -1) +
  ## custom labels
  labs(
    title = 'Bill Dimensions of Brush-Tailed Penguins (Pygoscelis)',
    subtitle = 'A scatter plot of bill depth versus bill length.',
    caption = 'Data: Gorman, Williams & Fraser (2014) PLoS ONE',
    x = 'Bill Length (mm)', 
    y = 'Bill Depth (mm)',
    color = 'Body mass (g)'
  )

{ggtext}

The ggtext package provides simple Markdown and HTML rendering for ggplot2. Under the hood, the package uses the gridtext package for the actual rendering, and consequently it is limited to the feature set provided by gridtext. Support is provided for Markdown both in theme elements (plot titles, subtitles, captions, axis labels, legends, etc.) and in geoms (similar to geom_text()). In both cases, there are two alternatives, one for creating simple text labels and one for creating text boxes with word wrapping.

element_markdown() → formatted text elements, e.g. titles, caption, axis text, striptext

## assign plot to `g` - we can ad new things to this plot later
## (wrapped in parenthesis so it is assigned and plotted in one step)
(gt <- ggplot(penguins, aes(x = bill_length_mm, y = bill_depth_mm)) +
  geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5) + 
  scale_x_continuous(breaks = 3:6 * 10, limits = c(30, 60)) +
  scale_y_continuous(breaks = seq(12.5, 22.5, by = 2.5), limits = c(12.5, 22.5)) +
  scico::scale_color_scico(palette = "bamako", direction = -1) +
  ## markdown formatting using asterisks
  labs(
    title = 'Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)',
    subtitle = 'A scatter plot of bill depth versus bill length.',
    caption = 'Data: Gorman, Williams & Fraser (2014) *PLoS ONE*',
    x = '**Bill Length** (mm)', 
    y = '**Bill Depth** (mm)',
    color = 'Body mass (g)'
  ) +
  ## render respective text elements
  theme(
    plot.title = ggtext::element_markdown(),
    plot.caption = ggtext::element_markdown(),
    axis.title.x = ggtext::element_markdown(),
    axis.title.y = ggtext::element_markdown()
  )
)

element_markdown() in combination with HTML

## use HTML syntax to change text color
gt_mar <- gt +
  labs(title = 'Bill Dimensions of Brush-Tailed Penguins <i style="color:#28A87D;">Pygoscelis</i>') +
  theme(plot.margin = margin(t = 25))

gt_mar

## use HTML syntax to change font and text size
gt_mar +
  labs(title = 'Bill Dimensions of Brush-Tailed Penguins <b style="font-size:32pt;font-family:blacksword;">Pygoscelis</b>')

gt_mar + 
  #labs(title = 'Bill Dimensions of Brush-Tailed Penguins <img src="https://researchgate.net/profile/Jean_Lightner/publication/274710342/figure/fig8/AS:614338578640906@1523481139381/Pygoscelis-papua-Source-Wikipedia-http-wwwenwikipediaorg.png"‚ width="100"/>') +
  ## title with missing quotation mark to make an erroneous pdf - 
  ## otherwise it throws an error because of RCurl on Windows OS
  labs(title = 'Bill Dimensions of Brush-Tailed Penguins <img src="https://researchgate.net/profile/Jean_Lightner/publication/274710342/figure/fig8/AS:614338578640906@1523481139381/Pygoscelis-papua-Source-Wikipedia-http-wwwenwikipediaorg.png‚ width="100"/>') 

geom_richtext() → formatted text labels with 360° rotation

gt_rich <- ggplot(penguins, aes(x = bill_length_mm, y = bill_depth_mm)) +
  geom_point(aes(color = species), alpha = .6, size = 3.5) + 
  ## add text annotations for each species
  ggtext::geom_richtext(
    data = tibble(
      x = c(34, 56, 54), y = c(20, 18.5, 14.5),
      species = c("Adélie", "Chinstrap", "Gentoo"),
      lab = c("<b style='font-family:anton;font-size:24pt;'>Adélie</b><br><i style='color:darkgrey;'>P. adéliae</i>", 
              "<b style='font-family:anton;font-size:24pt;'>Chinstrap</b><br><i style='color:darkgrey;'>P. antarctica</i>", 
              "<b style='font-family:anton;font-size:24pt;'>Gentoo</b><br><i style='color:darkgrey;'>P. papua</i>"),
      angle = c(12, 20, 335)
    ),
    aes(x, y, label = lab, color = species, angle = angle), 
    size = 4, fill = NA, label.color = NA,
    lineheight = .3
  ) +
  scale_x_continuous(breaks = 3:6 * 10, limits = c(30, 60)) +
  scale_y_continuous(breaks = seq(12.5, 22.5, by = 2.5), limits = c(12.5, 22.5)) +
  rcartocolor::scale_color_carto_d(palette = "Bold", guide = "none") +
  labs(
    title = 'Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)',
    subtitle = 'A scatter plot of bill depth versus bill length.',
    caption = 'Data: Gorman, Williams & Fraser (2014) *PLoS ONE*',
    x = '**Bill Length** (mm)', 
    y = '**Bill Depth** (mm)',
    color = 'Body mass (g)'
  )

(gt_rich +
  theme(
    plot.title = ggtext::element_markdown(),
    plot.caption = ggtext::element_markdown(),
    axis.title.x = ggtext::element_markdown(),
    axis.title.y = ggtext::element_markdown(),
    plot.margin = margin(25, 6, 15, 6)
  )
)

(gt_box <- gt_rich +
  theme(
    text = element_text(size=20),
    ## turn title into filled textbox
    plot.title = ggtext::element_textbox_simple(
      color = "white", fill = "#28A87D",  size = 32, 
      padding = margin(8, 4, 8, 4), margin = margin(b = 5), lineheight= .9
    ),
    ## add round outline to caption
    plot.caption = ggtext::element_textbox_simple(
      width = NULL, linetype = 1, padding = margin(4, 8, 4, 8), 
      margin = margin(t = 15), r = grid::unit(8, "pt"), size=24
    ),
    axis.title.x = ggtext::element_markdown(size=22),
    axis.title.y = ggtext::element_markdown(size=22),
    plot.margin = margin(25, 6, 15, 6)
  )
)

geom_textbox() → formatted text boxes with word wrapping

gt_box +
  ## add textbox with long paragraphs
  ggtext::geom_textbox(
    data = tibble(x = 34, y = 13.7, label = "<span style='font-size:12pt;font-family:anton;'>Lorem Ipsum Dolor Sit Amet</span><br><br>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."),
    aes(x, y, label = label),
    size = 2.2, family = "Open Sans",
    fill = "cornsilk", box.color = "cornsilk3",
    width = unit(11, "lines")
  ) +
  coord_cartesian(clip = "off")

{ggforce}

ggforce is a package aimed at providing missing functionality to ggplot2 through the extension system introduced with ggplot2 v2.0.0. Broadly speaking ggplot2 has been aimed primarily at explorative data visualization in order to investigate the data at hand, and less at providing utilities for composing custom plots a la D3.js. ggforce is mainly an attempt to address these “shortcoming” (design choices might be a better description). The goal is to provide a repository of geoms, stats, etc. that are as well documented and implemented as the official ones found in ggplot2.

## plot that we will annotate with gggforce afterwards
gf <- ggplot(penguins, aes(x = bill_length_mm, y = bill_depth_mm)) + 
  scico::scale_color_scico(palette = "bamako", direction = -1) +
  coord_cartesian(xlim = c(25, 65), ylim = c(10, 25)) +
  rcartocolor::scale_fill_carto_d(palette = "Bold") +
  labs(
    title = "Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)",
    subtitle = 'A scatter plot of bill depth versus bill length.',
    caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE*",
    x = "**Bill Length** (mm)", 
    y = "**Bill Depth** (mm)",
    color = "Body mass (g)",
    fill = "Species"
  )
 
## ellipsoids for all groups
(gf +
  ggforce::geom_mark_ellipse(
    aes(fill = species, label = species), 
    alpha = .15, show.legend = FALSE
  ) +
  geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5)
)

## ellipsoids for specific subset
(gf +
  ggforce::geom_mark_ellipse(
    aes(fill = species, label = species, filter = species == 'Gentoo'), 
    alpha = 0, show.legend = FALSE
  ) +
  geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5) +
  coord_cartesian(xlim = c(25, 65), ylim = c(10, 25))
)
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

## circles
(gf +
  ggforce::geom_mark_circle(
    aes(fill = species, label = species, filter = species == 'Gentoo'), 
    alpha = 0, show.legend = FALSE
  ) +
  geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5)
)

## rectangles
(gf +
  ggforce::geom_mark_rect(
    aes(fill = species, label = species, filter = species == 'Gentoo'), 
    alpha = 0, show.legend = FALSE
  ) +
  geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5) 
)

## hull
(gf +
  ggforce::geom_mark_hull(
    aes(fill = species, label = species, filter = species == 'Gentoo'), 
    alpha = 0, show.legend = FALSE
  ) +
  geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5)
)

ggplot Tricks

(gg0 <- 
  ggplot(penguins, aes(x = bill_length_mm, y = bill_depth_mm)) +
    ggforce::geom_mark_ellipse(
      aes(fill = species, label = species), 
      alpha = 0, show.legend = FALSE
    ) +
    geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5) + 
    scale_x_continuous(breaks = seq(25, 65, by = 5), limits = c(25, 65)) +
    scale_y_continuous(breaks = seq(12, 24, by = 2), limits = c(12, 24)) +
    scico::scale_color_scico(palette = "bamako", direction = -1) +
    labs(
      title = "Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)",
      subtitle = 'A scatter plot of bill depth versus bill length.',
      caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE*",
      x = "Bill Length (mm)", 
      y = "Bill Depth (mm)",
      color = "Body mass (g)"
    )
)

Left-Aligned Title

(gg1 <- gg0 + theme(plot.title.position = "plot"))

Right-Aligned Caption

(gg1b <- gg1 +  theme(plot.caption.position = "plot"))

Legend Design

(gg2 <- gg1b + theme(legend.position = "top"))

(gg2b <- gg2 + 
  guides(color = guide_colorbar(title.position = "top", 
                                title.hjust = .5, 
                                barwidth = unit(20, "lines"), 
                                barheight = unit(.5, "lines"))))

Limit Expansion

(gg3 <- gg2b + coord_cartesian(expand = FALSE))

Geeky Details: Clipping

(gg3b <- gg3 + coord_cartesian(expand = FALSE, clip = "off"))
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

White Space

(gg4 <- gg3b + theme(plot.margin = margin(t = 25, r = 25, b = 10, l = 25))) # top, right, bottom, left

Add Images

## read PNG file from web
png <- magick::image_read("https://raw.githubusercontent.com/allisonhorst/palmerpenguins/master/man/figures/culmen_depth.png")
## turn image into `rasterGrob`
img <- grid::rasterGrob(png, interpolate = TRUE)

(gg5 <- gg4 +
  annotation_custom(img, ymin = 21.5, ymax = 30.5, xmin = 55, xmax = 65.5) +
    labs(caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE* &bull; Illustration: Allison Horst"))

{patchwork}

The goal of patchwork is to make it ridiculously simple to combine separate ggplots into the same graphic. As such it tries to solve the same problem as gridExtra::grid.arrange() and cowplot::plot_grid but using an API that incites exploration and iteration, and scales to arbitrily complex layouts.

## calculate bill ratio and summary stats
df_peng_stats <- 
  penguins %>% 
  mutate(bill_ratio = bill_length_mm / bill_depth_mm) %>% 
  filter(!is.na(bill_ratio)) %>% 
  group_by(species) %>% 
  mutate(
    n = n(),
    median = median(bill_ratio),
    max = max(bill_ratio)
  ) %>% 
  ungroup() %>% 
  mutate(species_num = as.numeric(fct_rev(species))) 

## create a second chart with raincloud plots
p2 <- 
  ggplot(df_peng_stats, aes(bill_ratio, species_num, color = species)) +
  stat_summary(
    geom = "linerange",
    fun.min = function(x) -Inf,
    fun.max = function(x) median(x, na.rm = TRUE),
    linetype = "dotted",
    orientation = "y",
    size = .7
  ) +
  geom_point(
    aes(y = species_num - .15), 
    shape = "|",
    size = 5,
    alpha = .33
  ) +
  ggdist::stat_halfeye(
    aes(
      y = species_num,
      color = species,
      fill = after_scale(colorspace::lighten(color, .5))
    ),
    shape = 18,
    point_size = 3,
    interval_size = 1.8,
    adjust = .5,
    .width = c(0, 1)
  ) +
  geom_text(
    aes(x = median, label = format(round(median, 2), nsmall = 2)),
    stat = "unique",
    color = "white",
    family = "Open Sans",
    fontface = "bold",
    size = 3.4,
    nudge_y = .15
  ) +
  geom_text(
    aes(x = max, label = glue::glue("n = {n}")),
    stat = "unique",
    family = "Open Sans",
    fontface = "bold",
    size = 3.5,
    hjust = 0,
    nudge_x = .01,
    nudge_y = .02
  ) +
  coord_cartesian(clip = "off", expand = FALSE) +
  scale_x_continuous(
    limits = c(1.6, 3.8),
    breaks = seq(1.6, 3.8, by = .2)
  ) +
  scale_y_continuous(
    limits = c(.55, NA),
    breaks = 1:3,
    labels = c("Gentoo", "Chinstrap", "Adélie")
  ) +
  scale_color_manual(values = c("#3d6721", "#a86826", "#006c89"), guide = "none") +
  scale_fill_manual(values = c("#3d6721", "#a86826", "#006c89"), guide = "none") +
  labs(
    x = "Bill ratio",
    y = NULL,
    subtitle = "B. Raincloud plot shwoing the distribution of bill ratios, estimated as bill length divided by bill depth.",
    caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE* &bull; Illustration: Allison Horst"
  ) +
  theme(
    panel.grid.major.x = element_line(size = .35),
    panel.grid.major.y = element_blank(),
    axis.text.y = element_text(size = 13),
    axis.ticks.length = unit(0, "lines"),
    plot.title.position = 'plot',
    plot.subtitle = element_text(margin = margin(t = 5, b = 10)),
    plot.margin = margin(10, 25, 10, 25)
  )

p2

## combine both plots
(gg5 + labs(caption = NULL, subtitle = "A. Scatter plot of bill depth versus bill length.")) / p2 +
  plot_layout(heights = c(1, .65))

Another Example for Clipping

## with clipping
(on <- mtcars %>% 
  rownames_to_column() %>% 
  ggplot(aes(mpg, fct_reorder(rowname, mpg))) + 
    geom_point(size = 4, shape = "diamond", color = "firebrick") + 
    geom_text(aes(label = rowname), nudge_x = .35, hjust = 0, family = "Open Sans", size = 3.3) +     
    theme_void(base_size = 8, base_family = "Open Sans") + 
    theme(axis.line.x = element_line(color = "grey40"), 
          axis.text.x = element_text(color = "grey40"), 
          axis.ticks.x = element_line(color = "grey40"), 
          axis.ticks.length.x = unit(.4, "lines"), 
          plot.margin = margin(10, 45, 10, 20))
) 

on + coord_cartesian(clip = "off")

LS0tCnRpdGxlOiAiZ2dwbG90IFdpemFyZHJ5IEhhbmRzLU9uIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpyZWZlciB0bzogPGh0dHBzOi8vejN0dC5naXRodWIuaW8vT3V0bGllckNvbmYyMDIxLz9zPTA5PgoKYGBge3J9CmxvYWRlZFBhY2thZ2VzIDwtIGMoCiAgICAidGlkeXZlcnNlIiwgICAgICAgICMjIGRhdGEgc2NpZW5jZSBwYWNrYWdlIGNvbGxlY3Rpb24gKGluY2wuIHRoZSBnZ3Bsb3QyIHBhY2thZ2UpCiAgICAic3lzdGVtZm9udHMiLCAgICAgICMjIHVzZSBjdXN0b20gZm9udHMgKG5lZWRzIHRvIGJlIGluc3RhbGxlZCBvbiB5b3VyIE9TKQogICAgInNjaWNvIiwgICAgICAgICAgICAjIyBzY2ljbyBjb2xvciBwYWxldHRlcnMgKGh0dHA6Ly93d3cuZmFiaW9jcmFtZXJpLmNoL2NvbG91cm1hcHMucGhwKSBpbiBSIAogICAgImdndGV4dCIsICAgICAgICAgICAjIyBhZGQgaW1wcm92ZWQgdGV4dCByZW5kZXJpbmcgdG8gZ2dwbG90MgogICAgImdnZm9yY2UiLCAgICAgICAgICAjIyBhZGQgbWlzc2luZyBmdW5jdGlvbmFsaXR5IHRvIGdncGxvdDIKICAgICJnZ2Rpc3QiLCAgICAgICAgICAgIyMgYWRkIHVuY2VydGFpbnR5IHZpc3VhbGl6YXRpb24gdG8gZ2dwbG90MgogICAgIm1hZ2ljayIsICAgICAgICAgICAjIyBsb2FkIGltYWdlcyB0byBSCiAgICAicGF0Y2h3b3JrIiwgICAgICAgICMjIGNvbWJpbmUgb3V0cHV0cyBmcm9tIGdncGxvdDIKICAgICJJUmRpc3BsYXkiICAgICAgICAgIyMgJ0p1cHl0ZXInIERpc3BsYXkgTWFjaGluZXJ5CikKaW52aXNpYmxlKGxhcHBseShsb2FkZWRQYWNrYWdlcywgbGlicmFyeSwgY2hhcmFjdGVyLm9ubHk9VFJVRSwgdmVyYm9zZT1GQUxTRSwgd2Fybi5jb25mbGljdHM9RkFMU0UpKQpgYGAKCiMjIERhdGEKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKRGF0YSB3ZXJlIGNvbGxlY3RlZCBhbmQgbWFkZSBhdmFpbGFibGUgYnkgRHIuIEtyaXN0ZW4gR29ybWFuIGFuZCB0aGUgUGFsbWVyIFN0YXRpb24sIEFudGFyY3RpY2EgTFRFUiwgYSBtZW1iZXIgb2YgdGhlIExvbmcgVGVybSBFY29sb2dpY2FsIFJlc2VhcmNoIE5ldHdvcmsuCgpgYGB7cn0KcGVuZ3VpbnMgPC0gCiAgcmVhZHI6OnJlYWRfY3N2KCdodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vcmZvcmRhdGFzY2llbmNlL3RpZHl0dWVzZGF5L21hc3Rlci9kYXRhLzIwMjAvMjAyMC0wNy0yOC9wZW5ndWlucy5jc3YnKSAlPiUgCiAgIyMgY29ycmVjdCBzcGVjaWVzIG5hbWUKICBtdXRhdGUoc3BlY2llcyA9IGlmX2Vsc2Uoc3BlY2llcyA9PSAiQWRlbGllIiwgIkFkw6lsaWUiLCBzcGVjaWVzKSkgJT4lIAogICMjIHJlbW92ZSBtaXNzaW5nIG9ic2VydmF0aW9ucwogIGZpbHRlcighaXMubmEoYmlsbF9sZW5ndGhfbW0pLCAhaXMubmEoYmlsbF9kZXB0aF9tbSkpCgpwZW5ndWlucwpgYGAKCiMjIyBBIEJhc2ljIGdncGxvdAoKYGBge3IgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTEyfQojIyBzaW1wbGUgcGxvdDogZGF0YSArIG1hcHBpbmdzICsgZ2VvbWV0cnkKZ2dwbG90KHBlbmd1aW5zLCBhZXMoeCA9IGJpbGxfbGVuZ3RoX21tLCB5ID0gYmlsbF9kZXB0aF9tbSkpICsKICBnZW9tX3BvaW50KGFscGhhID0gLjYsIHNpemUgPSAzLjUpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCkpIApgYGAKCmBgYHtyIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMn0KIyMgY2hhbmdlIGdsb2JhbCB0aGVtZSBzZXR0aW5ncyAoZm9yIGFsbCBmb2xsb3dpbmcgcGxvdHMpCnRoZW1lX3NldCh0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE2LCBiYXNlX2ZhbWlseSA9ICJPcGVuIFNhbnMiKSkKCiMjIG1vZGlmeSBwbG90IGVsZW1lbnRzIGdsb2JhbGx5IChmb3IgYWxsIGZvbGxvd2luZyBwbG90cykKdGhlbWVfdXBkYXRlKAogIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiZ3JleTkyIiksCiAgYXhpcy50aWNrcy5sZW5ndGggPSB1bml0KC41LCAibGluZXMiKSwKICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImdyZXkzMCIpLAogIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIyLCBmYWNlID0gImJvbGQiKSwKICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgY29sb3IgPSAiZ3JleTMwIiksCiAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgbWFyZ2luID0gbWFyZ2luKHQgPSAxNSkpCikKZ2dwbG90KHBlbmd1aW5zLCBhZXMoeCA9IGJpbGxfbGVuZ3RoX21tLCB5ID0gYmlsbF9kZXB0aF9tbSkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGJvZHlfbWFzc19nKSwgYWxwaGEgPSAuNiwgc2l6ZSA9IDMuNSkgKyAKICAjIyBjdXN0b20gYXhlcyBzY2FsaW5nCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IDM6NiAqIDEwLCBsaW1pdHMgPSBjKDMwLCA2MCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDEyLjUsIDIyLjUsIGJ5ID0gMi41KSwgbGltaXRzID0gYygxMi41LCAyMi41KSkgKwogICMjIGN1c3RvbSBjb2xvcnMKICBzY2ljbzo6c2NhbGVfY29sb3Jfc2NpY28ocGFsZXR0ZSA9ICJiYW1ha28iLCBkaXJlY3Rpb24gPSAtMSkgKwogICMjIGN1c3RvbSBsYWJlbHMKICBsYWJzKAogICAgdGl0bGUgPSAnQmlsbCBEaW1lbnNpb25zIG9mIEJydXNoLVRhaWxlZCBQZW5ndWlucyAoUHlnb3NjZWxpcyknLAogICAgc3VidGl0bGUgPSAnQSBzY2F0dGVyIHBsb3Qgb2YgYmlsbCBkZXB0aCB2ZXJzdXMgYmlsbCBsZW5ndGguJywKICAgIGNhcHRpb24gPSAnRGF0YTogR29ybWFuLCBXaWxsaWFtcyAmIEZyYXNlciAoMjAxNCkgUExvUyBPTkUnLAogICAgeCA9ICdCaWxsIExlbmd0aCAobW0pJywgCiAgICB5ID0gJ0JpbGwgRGVwdGggKG1tKScsCiAgICBjb2xvciA9ICdCb2R5IG1hc3MgKGcpJwogICkKCmBgYAoKKip7Z2d0ZXh0fSoqCgo+IFRoZSBnZ3RleHQgcGFja2FnZSBwcm92aWRlcyBzaW1wbGUgTWFya2Rvd24gYW5kIEhUTUwgcmVuZGVyaW5nIGZvciBnZ3Bsb3QyLiBVbmRlciB0aGUgaG9vZCwgdGhlIHBhY2thZ2UgdXNlcyB0aGUgZ3JpZHRleHQgcGFja2FnZSBmb3IgdGhlIGFjdHVhbCByZW5kZXJpbmcsIGFuZCBjb25zZXF1ZW50bHkgaXQgaXMgbGltaXRlZCB0byB0aGUgZmVhdHVyZSBzZXQgcHJvdmlkZWQgYnkgZ3JpZHRleHQuIFN1cHBvcnQgaXMgcHJvdmlkZWQgZm9yIE1hcmtkb3duIGJvdGggaW4gdGhlbWUgZWxlbWVudHMgKHBsb3QgdGl0bGVzLCBzdWJ0aXRsZXMsIGNhcHRpb25zLCBheGlzIGxhYmVscywgbGVnZW5kcywgZXRjLikgYW5kIGluIGdlb21zIChzaW1pbGFyIHRvIGdlb21fdGV4dCgpKS4gSW4gYm90aCBjYXNlcywgdGhlcmUgYXJlIHR3byBhbHRlcm5hdGl2ZXMsIG9uZSBmb3IgY3JlYXRpbmcgc2ltcGxlIHRleHQgbGFiZWxzIGFuZCBvbmUgZm9yIGNyZWF0aW5nIHRleHQgYm94ZXMgd2l0aCB3b3JkIHdyYXBwaW5nLgoKZWxlbWVudF9tYXJrZG93bigpIOKGkiBmb3JtYXR0ZWQgdGV4dCBlbGVtZW50cywgZS5nLiB0aXRsZXMsIGNhcHRpb24sIGF4aXMgdGV4dCwgc3RyaXB0ZXh0CgpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CiMjIGFzc2lnbiBwbG90IHRvIGBnYCAtIHdlIGNhbiBhZCBuZXcgdGhpbmdzIHRvIHRoaXMgcGxvdCBsYXRlcgojIyAod3JhcHBlZCBpbiBwYXJlbnRoZXNpcyBzbyBpdCBpcyBhc3NpZ25lZCBhbmQgcGxvdHRlZCBpbiBvbmUgc3RlcCkKKGd0IDwtIGdncGxvdChwZW5ndWlucywgYWVzKHggPSBiaWxsX2xlbmd0aF9tbSwgeSA9IGJpbGxfZGVwdGhfbW0pKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBib2R5X21hc3NfZyksIGFscGhhID0gLjYsIHNpemUgPSAzLjUpICsgCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IDM6NiAqIDEwLCBsaW1pdHMgPSBjKDMwLCA2MCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDEyLjUsIDIyLjUsIGJ5ID0gMi41KSwgbGltaXRzID0gYygxMi41LCAyMi41KSkgKwogIHNjaWNvOjpzY2FsZV9jb2xvcl9zY2ljbyhwYWxldHRlID0gImJhbWFrbyIsIGRpcmVjdGlvbiA9IC0xKSArCiAgIyMgbWFya2Rvd24gZm9ybWF0dGluZyB1c2luZyBhc3Rlcmlza3MKICBsYWJzKAogICAgdGl0bGUgPSAnQmlsbCBEaW1lbnNpb25zIG9mIEJydXNoLVRhaWxlZCBQZW5ndWlucyAoKlB5Z29zY2VsaXMqKScsCiAgICBzdWJ0aXRsZSA9ICdBIHNjYXR0ZXIgcGxvdCBvZiBiaWxsIGRlcHRoIHZlcnN1cyBiaWxsIGxlbmd0aC4nLAogICAgY2FwdGlvbiA9ICdEYXRhOiBHb3JtYW4sIFdpbGxpYW1zICYgRnJhc2VyICgyMDE0KSAqUExvUyBPTkUqJywKICAgIHggPSAnKipCaWxsIExlbmd0aCoqIChtbSknLCAKICAgIHkgPSAnKipCaWxsIERlcHRoKiogKG1tKScsCiAgICBjb2xvciA9ICdCb2R5IG1hc3MgKGcpJwogICkgKwogICMjIHJlbmRlciByZXNwZWN0aXZlIHRleHQgZWxlbWVudHMKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBnZ3RleHQ6OmVsZW1lbnRfbWFya2Rvd24oKSwKICAgIHBsb3QuY2FwdGlvbiA9IGdndGV4dDo6ZWxlbWVudF9tYXJrZG93bigpLAogICAgYXhpcy50aXRsZS54ID0gZ2d0ZXh0OjplbGVtZW50X21hcmtkb3duKCksCiAgICBheGlzLnRpdGxlLnkgPSBnZ3RleHQ6OmVsZW1lbnRfbWFya2Rvd24oKQogICkKKQpgYGAKCmVsZW1lbnRfbWFya2Rvd24oKSBpbiBjb21iaW5hdGlvbiB3aXRoIEhUTUwKCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KIyMgdXNlIEhUTUwgc3ludGF4IHRvIGNoYW5nZSB0ZXh0IGNvbG9yCmd0X21hciA8LSBndCArCiAgbGFicyh0aXRsZSA9ICdCaWxsIERpbWVuc2lvbnMgb2YgQnJ1c2gtVGFpbGVkIFBlbmd1aW5zIDxpIHN0eWxlPSJjb2xvcjojMjhBODdEOyI+UHlnb3NjZWxpczwvaT4nKSArCiAgdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4odCA9IDI1KSkKCmd0X21hcgpgYGAKCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KIyMgdXNlIEhUTUwgc3ludGF4IHRvIGNoYW5nZSBmb250IGFuZCB0ZXh0IHNpemUKZ3RfbWFyICsKICBsYWJzKHRpdGxlID0gJ0JpbGwgRGltZW5zaW9ucyBvZiBCcnVzaC1UYWlsZWQgUGVuZ3VpbnMgPGIgc3R5bGU9ImZvbnQtc2l6ZTozMnB0O2ZvbnQtZmFtaWx5OmJsYWNrc3dvcmQ7Ij5QeWdvc2NlbGlzPC9iPicpCmBgYAoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwfQpndF9tYXIgKyAKICAjbGFicyh0aXRsZSA9ICdCaWxsIERpbWVuc2lvbnMgb2YgQnJ1c2gtVGFpbGVkIFBlbmd1aW5zIDxpbWcgc3JjPSJodHRwczovL3Jlc2VhcmNoZ2F0ZS5uZXQvcHJvZmlsZS9KZWFuX0xpZ2h0bmVyL3B1YmxpY2F0aW9uLzI3NDcxMDM0Mi9maWd1cmUvZmlnOC9BUzo2MTQzMzg1Nzg2NDA5MDZAMTUyMzQ4MTEzOTM4MS9QeWdvc2NlbGlzLXBhcHVhLVNvdXJjZS1XaWtpcGVkaWEtaHR0cC13d3dlbndpa2lwZWRpYW9yZy5wbmci4oCaIHdpZHRoPSIxMDAiLz4nKSArCiAgIyMgdGl0bGUgd2l0aCBtaXNzaW5nIHF1b3RhdGlvbiBtYXJrIHRvIG1ha2UgYW4gZXJyb25lb3VzIHBkZiAtIAogICMjIG90aGVyd2lzZSBpdCB0aHJvd3MgYW4gZXJyb3IgYmVjYXVzZSBvZiBSQ3VybCBvbiBXaW5kb3dzIE9TCiAgbGFicyh0aXRsZSA9ICdCaWxsIERpbWVuc2lvbnMgb2YgQnJ1c2gtVGFpbGVkIFBlbmd1aW5zIDxpbWcgc3JjPSJodHRwczovL3Jlc2VhcmNoZ2F0ZS5uZXQvcHJvZmlsZS9KZWFuX0xpZ2h0bmVyL3B1YmxpY2F0aW9uLzI3NDcxMDM0Mi9maWd1cmUvZmlnOC9BUzo2MTQzMzg1Nzg2NDA5MDZAMTUyMzQ4MTEzOTM4MS9QeWdvc2NlbGlzLXBhcHVhLVNvdXJjZS1XaWtpcGVkaWEtaHR0cC13d3dlbndpa2lwZWRpYW9yZy5wbmfigJogd2lkdGg9IjEwMCIvPicpIApgYGAKCmdlb21fcmljaHRleHQoKSDihpIgZm9ybWF0dGVkIHRleHQgbGFiZWxzIHdpdGggMzYwwrAgcm90YXRpb24KCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KZ3RfcmljaCA8LSBnZ3Bsb3QocGVuZ3VpbnMsIGFlcyh4ID0gYmlsbF9sZW5ndGhfbW0sIHkgPSBiaWxsX2RlcHRoX21tKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gc3BlY2llcyksIGFscGhhID0gLjYsIHNpemUgPSAzLjUpICsgCiAgIyMgYWRkIHRleHQgYW5ub3RhdGlvbnMgZm9yIGVhY2ggc3BlY2llcwogIGdndGV4dDo6Z2VvbV9yaWNodGV4dCgKICAgIGRhdGEgPSB0aWJibGUoCiAgICAgIHggPSBjKDM0LCA1NiwgNTQpLCB5ID0gYygyMCwgMTguNSwgMTQuNSksCiAgICAgIHNwZWNpZXMgPSBjKCJBZMOpbGllIiwgIkNoaW5zdHJhcCIsICJHZW50b28iKSwKICAgICAgbGFiID0gYygiPGIgc3R5bGU9J2ZvbnQtZmFtaWx5OmFudG9uO2ZvbnQtc2l6ZToyNHB0Oyc+QWTDqWxpZTwvYj48YnI+PGkgc3R5bGU9J2NvbG9yOmRhcmtncmV5Oyc+UC4gYWTDqWxpYWU8L2k+IiwgCiAgICAgICAgICAgICAgIjxiIHN0eWxlPSdmb250LWZhbWlseTphbnRvbjtmb250LXNpemU6MjRwdDsnPkNoaW5zdHJhcDwvYj48YnI+PGkgc3R5bGU9J2NvbG9yOmRhcmtncmV5Oyc+UC4gYW50YXJjdGljYTwvaT4iLCAKICAgICAgICAgICAgICAiPGIgc3R5bGU9J2ZvbnQtZmFtaWx5OmFudG9uO2ZvbnQtc2l6ZToyNHB0Oyc+R2VudG9vPC9iPjxicj48aSBzdHlsZT0nY29sb3I6ZGFya2dyZXk7Jz5QLiBwYXB1YTwvaT4iKSwKICAgICAgYW5nbGUgPSBjKDEyLCAyMCwgMzM1KQogICAgKSwKICAgIGFlcyh4LCB5LCBsYWJlbCA9IGxhYiwgY29sb3IgPSBzcGVjaWVzLCBhbmdsZSA9IGFuZ2xlKSwgCiAgICBzaXplID0gNCwgZmlsbCA9IE5BLCBsYWJlbC5jb2xvciA9IE5BLAogICAgbGluZWhlaWdodCA9IC4zCiAgKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IDM6NiAqIDEwLCBsaW1pdHMgPSBjKDMwLCA2MCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDEyLjUsIDIyLjUsIGJ5ID0gMi41KSwgbGltaXRzID0gYygxMi41LCAyMi41KSkgKwogIHJjYXJ0b2NvbG9yOjpzY2FsZV9jb2xvcl9jYXJ0b19kKHBhbGV0dGUgPSAiQm9sZCIsIGd1aWRlID0gIm5vbmUiKSArCiAgbGFicygKICAgIHRpdGxlID0gJ0JpbGwgRGltZW5zaW9ucyBvZiBCcnVzaC1UYWlsZWQgUGVuZ3VpbnMgKCpQeWdvc2NlbGlzKiknLAogICAgc3VidGl0bGUgPSAnQSBzY2F0dGVyIHBsb3Qgb2YgYmlsbCBkZXB0aCB2ZXJzdXMgYmlsbCBsZW5ndGguJywKICAgIGNhcHRpb24gPSAnRGF0YTogR29ybWFuLCBXaWxsaWFtcyAmIEZyYXNlciAoMjAxNCkgKlBMb1MgT05FKicsCiAgICB4ID0gJyoqQmlsbCBMZW5ndGgqKiAobW0pJywgCiAgICB5ID0gJyoqQmlsbCBEZXB0aCoqIChtbSknLAogICAgY29sb3IgPSAnQm9keSBtYXNzIChnKScKICApCgooZ3RfcmljaCArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZ2d0ZXh0OjplbGVtZW50X21hcmtkb3duKCksCiAgICBwbG90LmNhcHRpb24gPSBnZ3RleHQ6OmVsZW1lbnRfbWFya2Rvd24oKSwKICAgIGF4aXMudGl0bGUueCA9IGdndGV4dDo6ZWxlbWVudF9tYXJrZG93bigpLAogICAgYXhpcy50aXRsZS55ID0gZ2d0ZXh0OjplbGVtZW50X21hcmtkb3duKCksCiAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbigyNSwgNiwgMTUsIDYpCiAgKQopCmBgYAoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwfQooZ3RfYm94IDwtIGd0X3JpY2ggKwogIHRoZW1lKAogICAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSwKICAgICMjIHR1cm4gdGl0bGUgaW50byBmaWxsZWQgdGV4dGJveAogICAgcGxvdC50aXRsZSA9IGdndGV4dDo6ZWxlbWVudF90ZXh0Ym94X3NpbXBsZSgKICAgICAgY29sb3IgPSAid2hpdGUiLCBmaWxsID0gIiMyOEE4N0QiLCAgc2l6ZSA9IDMyLCAKICAgICAgcGFkZGluZyA9IG1hcmdpbig4LCA0LCA4LCA0KSwgbWFyZ2luID0gbWFyZ2luKGIgPSA1KSwgbGluZWhlaWdodD0gLjkKICAgICksCiAgICAjIyBhZGQgcm91bmQgb3V0bGluZSB0byBjYXB0aW9uCiAgICBwbG90LmNhcHRpb24gPSBnZ3RleHQ6OmVsZW1lbnRfdGV4dGJveF9zaW1wbGUoCiAgICAgIHdpZHRoID0gTlVMTCwgbGluZXR5cGUgPSAxLCBwYWRkaW5nID0gbWFyZ2luKDQsIDgsIDQsIDgpLCAKICAgICAgbWFyZ2luID0gbWFyZ2luKHQgPSAxNSksIHIgPSBncmlkOjp1bml0KDgsICJwdCIpLCBzaXplPTI0CiAgICApLAogICAgYXhpcy50aXRsZS54ID0gZ2d0ZXh0OjplbGVtZW50X21hcmtkb3duKHNpemU9MjIpLAogICAgYXhpcy50aXRsZS55ID0gZ2d0ZXh0OjplbGVtZW50X21hcmtkb3duKHNpemU9MjIpLAogICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMjUsIDYsIDE1LCA2KQogICkKKQpgYGAKCmdlb21fdGV4dGJveCgpIOKGkiBmb3JtYXR0ZWQgdGV4dCBib3hlcyB3aXRoIHdvcmQgd3JhcHBpbmcKCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KZ3RfYm94ICsKICAjIyBhZGQgdGV4dGJveCB3aXRoIGxvbmcgcGFyYWdyYXBocwogIGdndGV4dDo6Z2VvbV90ZXh0Ym94KAogICAgZGF0YSA9IHRpYmJsZSh4ID0gMzQsIHkgPSAxMy43LCBsYWJlbCA9ICI8c3BhbiBzdHlsZT0nZm9udC1zaXplOjEycHQ7Zm9udC1mYW1pbHk6YW50b247Jz5Mb3JlbSBJcHN1bSBEb2xvciBTaXQgQW1ldDwvc3Bhbj48YnI+PGJyPkxvcmVtIGlwc3VtIGRvbG9yIHNpdCBhbWV0LCBjb25zZWN0ZXR1ciBhZGlwaXNjaW5nIGVsaXQsIHNlZCBkbyBlaXVzbW9kIHRlbXBvciBpbmNpZGlkdW50IHV0IGxhYm9yZSBldCBkb2xvcmUgbWFnbmEgYWxpcXVhLiBVdCBlbmltIGFkIG1pbmltIHZlbmlhbSwgcXVpcyBub3N0cnVkIGV4ZXJjaXRhdGlvbiB1bGxhbWNvIGxhYm9yaXMgbmlzaSB1dCBhbGlxdWlwIGV4IGVhIGNvbW1vZG8gY29uc2VxdWF0LiBEdWlzIGF1dGUgaXJ1cmUgZG9sb3IgaW4gcmVwcmVoZW5kZXJpdCBpbiB2b2x1cHRhdGUgdmVsaXQgZXNzZSBjaWxsdW0gZG9sb3JlIGV1IGZ1Z2lhdCBudWxsYSBwYXJpYXR1ci4gRXhjZXB0ZXVyIHNpbnQgb2NjYWVjYXQgY3VwaWRhdGF0IG5vbiBwcm9pZGVudCwgc3VudCBpbiBjdWxwYSBxdWkgb2ZmaWNpYSBkZXNlcnVudCBtb2xsaXQgYW5pbSBpZCBlc3QgbGFib3J1bS4iKSwKICAgIGFlcyh4LCB5LCBsYWJlbCA9IGxhYmVsKSwKICAgIHNpemUgPSAyLjIsIGZhbWlseSA9ICJPcGVuIFNhbnMiLAogICAgZmlsbCA9ICJjb3Juc2lsayIsIGJveC5jb2xvciA9ICJjb3Juc2lsazMiLAogICAgd2lkdGggPSB1bml0KDExLCAibGluZXMiKQogICkgKwogIGNvb3JkX2NhcnRlc2lhbihjbGlwID0gIm9mZiIpCmBgYAoKKip7Z2dmb3JjZX0qKgoKPiBnZ2ZvcmNlIGlzIGEgcGFja2FnZSBhaW1lZCBhdCBwcm92aWRpbmcgbWlzc2luZyBmdW5jdGlvbmFsaXR5IHRvIGdncGxvdDIgdGhyb3VnaCB0aGUgZXh0ZW5zaW9uIHN5c3RlbSBpbnRyb2R1Y2VkIHdpdGggZ2dwbG90MiB2Mi4wLjAuIEJyb2FkbHkgc3BlYWtpbmcgZ2dwbG90MiBoYXMgYmVlbiBhaW1lZCBwcmltYXJpbHkgYXQgZXhwbG9yYXRpdmUgZGF0YSB2aXN1YWxpemF0aW9uIGluIG9yZGVyIHRvIGludmVzdGlnYXRlIHRoZSBkYXRhIGF0IGhhbmQsIGFuZCBsZXNzIGF0IHByb3ZpZGluZyB1dGlsaXRpZXMgZm9yIGNvbXBvc2luZyBjdXN0b20gcGxvdHMgYSBsYSBEMy5qcy4gZ2dmb3JjZSBpcyBtYWlubHkgYW4gYXR0ZW1wdCB0byBhZGRyZXNzIHRoZXNlICJzaG9ydGNvbWluZyIgKGRlc2lnbiBjaG9pY2VzIG1pZ2h0IGJlIGEgYmV0dGVyIGRlc2NyaXB0aW9uKS4gVGhlIGdvYWwgaXMgdG8gcHJvdmlkZSBhIHJlcG9zaXRvcnkgb2YgZ2VvbXMsIHN0YXRzLCBldGMuIHRoYXQgYXJlIGFzIHdlbGwgZG9jdW1lbnRlZCBhbmQgaW1wbGVtZW50ZWQgYXMgdGhlIG9mZmljaWFsIG9uZXMgZm91bmQgaW4gZ2dwbG90Mi4KCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KIyMgcGxvdCB0aGF0IHdlIHdpbGwgYW5ub3RhdGUgd2l0aCBnZ2dmb3JjZSBhZnRlcndhcmRzCmdmIDwtIGdncGxvdChwZW5ndWlucywgYWVzKHggPSBiaWxsX2xlbmd0aF9tbSwgeSA9IGJpbGxfZGVwdGhfbW0pKSArIAogIHNjaWNvOjpzY2FsZV9jb2xvcl9zY2ljbyhwYWxldHRlID0gImJhbWFrbyIsIGRpcmVjdGlvbiA9IC0xKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDI1LCA2NSksIHlsaW0gPSBjKDEwLCAyNSkpICsKICByY2FydG9jb2xvcjo6c2NhbGVfZmlsbF9jYXJ0b19kKHBhbGV0dGUgPSAiQm9sZCIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiQmlsbCBEaW1lbnNpb25zIG9mIEJydXNoLVRhaWxlZCBQZW5ndWlucyAoKlB5Z29zY2VsaXMqKSIsCiAgICBzdWJ0aXRsZSA9ICdBIHNjYXR0ZXIgcGxvdCBvZiBiaWxsIGRlcHRoIHZlcnN1cyBiaWxsIGxlbmd0aC4nLAogICAgY2FwdGlvbiA9ICJEYXRhOiBHb3JtYW4sIFdpbGxpYW1zICYgRnJhc2VyICgyMDE0KSAqUExvUyBPTkUqIiwKICAgIHggPSAiKipCaWxsIExlbmd0aCoqIChtbSkiLCAKICAgIHkgPSAiKipCaWxsIERlcHRoKiogKG1tKSIsCiAgICBjb2xvciA9ICJCb2R5IG1hc3MgKGcpIiwKICAgIGZpbGwgPSAiU3BlY2llcyIKICApCiAKIyMgZWxsaXBzb2lkcyBmb3IgYWxsIGdyb3VwcwooZ2YgKwogIGdnZm9yY2U6Omdlb21fbWFya19lbGxpcHNlKAogICAgYWVzKGZpbGwgPSBzcGVjaWVzLCBsYWJlbCA9IHNwZWNpZXMpLCAKICAgIGFscGhhID0gLjE1LCBzaG93LmxlZ2VuZCA9IEZBTFNFCiAgKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBib2R5X21hc3NfZyksIGFscGhhID0gLjYsIHNpemUgPSAzLjUpCikKCmBgYAoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwfQojIyBlbGxpcHNvaWRzIGZvciBzcGVjaWZpYyBzdWJzZXQKKGdmICsKICBnZ2ZvcmNlOjpnZW9tX21hcmtfZWxsaXBzZSgKICAgIGFlcyhmaWxsID0gc3BlY2llcywgbGFiZWwgPSBzcGVjaWVzLCBmaWx0ZXIgPSBzcGVjaWVzID09ICdHZW50b28nKSwgCiAgICBhbHBoYSA9IDAsIHNob3cubGVnZW5kID0gRkFMU0UKICApICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGJvZHlfbWFzc19nKSwgYWxwaGEgPSAuNiwgc2l6ZSA9IDMuNSkgKwogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygyNSwgNjUpLCB5bGltID0gYygxMCwgMjUpKQopCmBgYAoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwfQojIyBjaXJjbGVzCihnZiArCiAgZ2dmb3JjZTo6Z2VvbV9tYXJrX2NpcmNsZSgKICAgIGFlcyhmaWxsID0gc3BlY2llcywgbGFiZWwgPSBzcGVjaWVzLCBmaWx0ZXIgPSBzcGVjaWVzID09ICdHZW50b28nKSwgCiAgICBhbHBoYSA9IDAsIHNob3cubGVnZW5kID0gRkFMU0UKICApICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGJvZHlfbWFzc19nKSwgYWxwaGEgPSAuNiwgc2l6ZSA9IDMuNSkKKQpgYGAKCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KIyMgcmVjdGFuZ2xlcwooZ2YgKwogIGdnZm9yY2U6Omdlb21fbWFya19yZWN0KAogICAgYWVzKGZpbGwgPSBzcGVjaWVzLCBsYWJlbCA9IHNwZWNpZXMsIGZpbHRlciA9IHNwZWNpZXMgPT0gJ0dlbnRvbycpLCAKICAgIGFscGhhID0gMCwgc2hvdy5sZWdlbmQgPSBGQUxTRQogICkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gYm9keV9tYXNzX2cpLCBhbHBoYSA9IC42LCBzaXplID0gMy41KSAKKQpgYGAKCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KIyMgaHVsbAooZ2YgKwogIGdnZm9yY2U6Omdlb21fbWFya19odWxsKAogICAgYWVzKGZpbGwgPSBzcGVjaWVzLCBsYWJlbCA9IHNwZWNpZXMsIGZpbHRlciA9IHNwZWNpZXMgPT0gJ0dlbnRvbycpLCAKICAgIGFscGhhID0gMCwgc2hvdy5sZWdlbmQgPSBGQUxTRQogICkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gYm9keV9tYXNzX2cpLCBhbHBoYSA9IC42LCBzaXplID0gMy41KQopCmBgYAoKIyMjIGdncGxvdCBUcmlja3MKCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KKGdnMCA8LSAKICBnZ3Bsb3QocGVuZ3VpbnMsIGFlcyh4ID0gYmlsbF9sZW5ndGhfbW0sIHkgPSBiaWxsX2RlcHRoX21tKSkgKwogICAgZ2dmb3JjZTo6Z2VvbV9tYXJrX2VsbGlwc2UoCiAgICAgIGFlcyhmaWxsID0gc3BlY2llcywgbGFiZWwgPSBzcGVjaWVzKSwgCiAgICAgIGFscGhhID0gMCwgc2hvdy5sZWdlbmQgPSBGQUxTRQogICAgKSArCiAgICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGJvZHlfbWFzc19nKSwgYWxwaGEgPSAuNiwgc2l6ZSA9IDMuNSkgKyAKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMjUsIDY1LCBieSA9IDUpLCBsaW1pdHMgPSBjKDI1LCA2NSkpICsKICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMTIsIDI0LCBieSA9IDIpLCBsaW1pdHMgPSBjKDEyLCAyNCkpICsKICAgIHNjaWNvOjpzY2FsZV9jb2xvcl9zY2ljbyhwYWxldHRlID0gImJhbWFrbyIsIGRpcmVjdGlvbiA9IC0xKSArCiAgICBsYWJzKAogICAgICB0aXRsZSA9ICJCaWxsIERpbWVuc2lvbnMgb2YgQnJ1c2gtVGFpbGVkIFBlbmd1aW5zICgqUHlnb3NjZWxpcyopIiwKICAgICAgc3VidGl0bGUgPSAnQSBzY2F0dGVyIHBsb3Qgb2YgYmlsbCBkZXB0aCB2ZXJzdXMgYmlsbCBsZW5ndGguJywKICAgICAgY2FwdGlvbiA9ICJEYXRhOiBHb3JtYW4sIFdpbGxpYW1zICYgRnJhc2VyICgyMDE0KSAqUExvUyBPTkUqIiwKICAgICAgeCA9ICJCaWxsIExlbmd0aCAobW0pIiwgCiAgICAgIHkgPSAiQmlsbCBEZXB0aCAobW0pIiwKICAgICAgY29sb3IgPSAiQm9keSBtYXNzIChnKSIKICAgICkKKQpgYGAKCiMjIyBMZWZ0LUFsaWduZWQgVGl0bGUKCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KKGdnMSA8LSBnZzAgKyB0aGVtZShwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiKSkKYGBgCgojIyMgUmlnaHQtQWxpZ25lZCBDYXB0aW9uCgpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CihnZzFiIDwtIGdnMSArICB0aGVtZShwbG90LmNhcHRpb24ucG9zaXRpb24gPSAicGxvdCIpKQpgYGAKCiMjIyBMZWdlbmQgRGVzaWduCgpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CihnZzIgPC0gZ2cxYiArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSkKYGBgCgpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CihnZzJiIDwtIGdnMiArIAogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2NvbG9yYmFyKHRpdGxlLnBvc2l0aW9uID0gInRvcCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlLmhqdXN0ID0gLjUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhcndpZHRoID0gdW5pdCgyMCwgImxpbmVzIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhcmhlaWdodCA9IHVuaXQoLjUsICJsaW5lcyIpKSkpCmBgYAoKIyMjIExpbWl0IEV4cGFuc2lvbgoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwfQooZ2czIDwtIGdnMmIgKyBjb29yZF9jYXJ0ZXNpYW4oZXhwYW5kID0gRkFMU0UpKQpgYGAKCiMjIyBHZWVreSBEZXRhaWxzOiBDbGlwcGluZwoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwfQooZ2czYiA8LSBnZzMgKyBjb29yZF9jYXJ0ZXNpYW4oZXhwYW5kID0gRkFMU0UsIGNsaXAgPSAib2ZmIikpCmBgYAoKIyMjIFdoaXRlIFNwYWNlCgpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CihnZzQgPC0gZ2czYiArIHRoZW1lKHBsb3QubWFyZ2luID0gbWFyZ2luKHQgPSAyNSwgciA9IDI1LCBiID0gMTAsIGwgPSAyNSkpKSAjIHRvcCwgcmlnaHQsIGJvdHRvbSwgbGVmdApgYGAKCiMjIyBBZGQgSW1hZ2VzCgpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CiMjIHJlYWQgUE5HIGZpbGUgZnJvbSB3ZWIKcG5nIDwtIG1hZ2ljazo6aW1hZ2VfcmVhZCgiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2FsbGlzb25ob3JzdC9wYWxtZXJwZW5ndWlucy9tYXN0ZXIvbWFuL2ZpZ3VyZXMvY3VsbWVuX2RlcHRoLnBuZyIpCiMjIHR1cm4gaW1hZ2UgaW50byBgcmFzdGVyR3JvYmAKaW1nIDwtIGdyaWQ6OnJhc3Rlckdyb2IocG5nLCBpbnRlcnBvbGF0ZSA9IFRSVUUpCgooZ2c1IDwtIGdnNCArCiAgYW5ub3RhdGlvbl9jdXN0b20oaW1nLCB5bWluID0gMjEuNSwgeW1heCA9IDMwLjUsIHhtaW4gPSA1NSwgeG1heCA9IDY1LjUpICsKICAgIGxhYnMoY2FwdGlvbiA9ICJEYXRhOiBHb3JtYW4sIFdpbGxpYW1zICYgRnJhc2VyICgyMDE0KSAqUExvUyBPTkUqICZidWxsOyBJbGx1c3RyYXRpb246IEFsbGlzb24gSG9yc3QiKSkKYGBgCgoqKntwYXRjaHdvcmt9KioKCj4gVGhlIGdvYWwgb2YgcGF0Y2h3b3JrIGlzIHRvIG1ha2UgaXQgcmlkaWN1bG91c2x5IHNpbXBsZSB0byBjb21iaW5lIHNlcGFyYXRlIGdncGxvdHMgaW50byB0aGUgc2FtZSBncmFwaGljLiBBcyBzdWNoIGl0IHRyaWVzIHRvIHNvbHZlIHRoZSBzYW1lIHByb2JsZW0gYXMgZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UoKSBhbmQgY293cGxvdDo6cGxvdF9ncmlkIGJ1dCB1c2luZyBhbiBBUEkgdGhhdCBpbmNpdGVzIGV4cGxvcmF0aW9uIGFuZCBpdGVyYXRpb24sIGFuZCBzY2FsZXMgdG8gYXJiaXRyaWx5IGNvbXBsZXggbGF5b3V0cy4KCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KIyMgY2FsY3VsYXRlIGJpbGwgcmF0aW8gYW5kIHN1bW1hcnkgc3RhdHMKZGZfcGVuZ19zdGF0cyA8LSAKICBwZW5ndWlucyAlPiUgCiAgbXV0YXRlKGJpbGxfcmF0aW8gPSBiaWxsX2xlbmd0aF9tbSAvIGJpbGxfZGVwdGhfbW0pICU+JSAKICBmaWx0ZXIoIWlzLm5hKGJpbGxfcmF0aW8pKSAlPiUgCiAgZ3JvdXBfYnkoc3BlY2llcykgJT4lIAogIG11dGF0ZSgKICAgIG4gPSBuKCksCiAgICBtZWRpYW4gPSBtZWRpYW4oYmlsbF9yYXRpbyksCiAgICBtYXggPSBtYXgoYmlsbF9yYXRpbykKICApICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIG11dGF0ZShzcGVjaWVzX251bSA9IGFzLm51bWVyaWMoZmN0X3JldihzcGVjaWVzKSkpIAoKIyMgY3JlYXRlIGEgc2Vjb25kIGNoYXJ0IHdpdGggcmFpbmNsb3VkIHBsb3RzCnAyIDwtIAogIGdncGxvdChkZl9wZW5nX3N0YXRzLCBhZXMoYmlsbF9yYXRpbywgc3BlY2llc19udW0sIGNvbG9yID0gc3BlY2llcykpICsKICBzdGF0X3N1bW1hcnkoCiAgICBnZW9tID0gImxpbmVyYW5nZSIsCiAgICBmdW4ubWluID0gZnVuY3Rpb24oeCkgLUluZiwKICAgIGZ1bi5tYXggPSBmdW5jdGlvbih4KSBtZWRpYW4oeCwgbmEucm0gPSBUUlVFKSwKICAgIGxpbmV0eXBlID0gImRvdHRlZCIsCiAgICBvcmllbnRhdGlvbiA9ICJ5IiwKICAgIHNpemUgPSAuNwogICkgKwogIGdlb21fcG9pbnQoCiAgICBhZXMoeSA9IHNwZWNpZXNfbnVtIC0gLjE1KSwgCiAgICBzaGFwZSA9ICJ8IiwKICAgIHNpemUgPSA1LAogICAgYWxwaGEgPSAuMzMKICApICsKICBnZ2Rpc3Q6OnN0YXRfaGFsZmV5ZSgKICAgIGFlcygKICAgICAgeSA9IHNwZWNpZXNfbnVtLAogICAgICBjb2xvciA9IHNwZWNpZXMsCiAgICAgIGZpbGwgPSBhZnRlcl9zY2FsZShjb2xvcnNwYWNlOjpsaWdodGVuKGNvbG9yLCAuNSkpCiAgICApLAogICAgc2hhcGUgPSAxOCwKICAgIHBvaW50X3NpemUgPSAzLAogICAgaW50ZXJ2YWxfc2l6ZSA9IDEuOCwKICAgIGFkanVzdCA9IC41LAogICAgLndpZHRoID0gYygwLCAxKQogICkgKwogIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gbWVkaWFuLCBsYWJlbCA9IGZvcm1hdChyb3VuZChtZWRpYW4sIDIpLCBuc21hbGwgPSAyKSksCiAgICBzdGF0ID0gInVuaXF1ZSIsCiAgICBjb2xvciA9ICJ3aGl0ZSIsCiAgICBmYW1pbHkgPSAiT3BlbiBTYW5zIiwKICAgIGZvbnRmYWNlID0gImJvbGQiLAogICAgc2l6ZSA9IDMuNCwKICAgIG51ZGdlX3kgPSAuMTUKICApICsKICBnZW9tX3RleHQoCiAgICBhZXMoeCA9IG1heCwgbGFiZWwgPSBnbHVlOjpnbHVlKCJuID0ge259IikpLAogICAgc3RhdCA9ICJ1bmlxdWUiLAogICAgZmFtaWx5ID0gIk9wZW4gU2FucyIsCiAgICBmb250ZmFjZSA9ICJib2xkIiwKICAgIHNpemUgPSAzLjUsCiAgICBoanVzdCA9IDAsCiAgICBudWRnZV94ID0gLjAxLAogICAgbnVkZ2VfeSA9IC4wMgogICkgKwogIGNvb3JkX2NhcnRlc2lhbihjbGlwID0gIm9mZiIsIGV4cGFuZCA9IEZBTFNFKSArCiAgc2NhbGVfeF9jb250aW51b3VzKAogICAgbGltaXRzID0gYygxLjYsIDMuOCksCiAgICBicmVha3MgPSBzZXEoMS42LCAzLjgsIGJ5ID0gLjIpCiAgKSArCiAgc2NhbGVfeV9jb250aW51b3VzKAogICAgbGltaXRzID0gYyguNTUsIE5BKSwKICAgIGJyZWFrcyA9IDE6MywKICAgIGxhYmVscyA9IGMoIkdlbnRvbyIsICJDaGluc3RyYXAiLCAiQWTDqWxpZSIpCiAgKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiMzZDY3MjEiLCAiI2E4NjgyNiIsICIjMDA2Yzg5IiksIGd1aWRlID0gIm5vbmUiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzNkNjcyMSIsICIjYTg2ODI2IiwgIiMwMDZjODkiKSwgZ3VpZGUgPSAibm9uZSIpICsKICBsYWJzKAogICAgeCA9ICJCaWxsIHJhdGlvIiwKICAgIHkgPSBOVUxMLAogICAgc3VidGl0bGUgPSAiQi4gUmFpbmNsb3VkIHBsb3Qgc2h3b2luZyB0aGUgZGlzdHJpYnV0aW9uIG9mIGJpbGwgcmF0aW9zLCBlc3RpbWF0ZWQgYXMgYmlsbCBsZW5ndGggZGl2aWRlZCBieSBiaWxsIGRlcHRoLiIsCiAgICBjYXB0aW9uID0gIkRhdGE6IEdvcm1hbiwgV2lsbGlhbXMgJiBGcmFzZXIgKDIwMTQpICpQTG9TIE9ORSogJmJ1bGw7IElsbHVzdHJhdGlvbjogQWxsaXNvbiBIb3JzdCIKICApICsKICB0aGVtZSgKICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfbGluZShzaXplID0gLjM1KSwKICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMyksCiAgICBheGlzLnRpY2tzLmxlbmd0aCA9IHVuaXQoMCwgImxpbmVzIiksCiAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gJ3Bsb3QnLAogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4odCA9IDUsIGIgPSAxMCkpLAogICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMTAsIDI1LCAxMCwgMjUpCiAgKQoKcDIKYGBgCgpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CiMjIGNvbWJpbmUgYm90aCBwbG90cwooZ2c1ICsgbGFicyhjYXB0aW9uID0gTlVMTCwgc3VidGl0bGUgPSAiQS4gU2NhdHRlciBwbG90IG9mIGJpbGwgZGVwdGggdmVyc3VzIGJpbGwgbGVuZ3RoLiIpKSAvIHAyICsKICBwbG90X2xheW91dChoZWlnaHRzID0gYygxLCAuNjUpKQpgYGAKCiMjIEFub3RoZXIgRXhhbXBsZSBmb3IgQ2xpcHBpbmcKCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KIyMgd2l0aCBjbGlwcGluZwoob24gPC0gbXRjYXJzICU+JSAKICByb3duYW1lc190b19jb2x1bW4oKSAlPiUgCiAgZ2dwbG90KGFlcyhtcGcsIGZjdF9yZW9yZGVyKHJvd25hbWUsIG1wZykpKSArIAogICAgZ2VvbV9wb2ludChzaXplID0gNCwgc2hhcGUgPSAiZGlhbW9uZCIsIGNvbG9yID0gImZpcmVicmljayIpICsgCiAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm93bmFtZSksIG51ZGdlX3ggPSAuMzUsIGhqdXN0ID0gMCwgZmFtaWx5ID0gIk9wZW4gU2FucyIsIHNpemUgPSAzLjMpICsgICAgIAogICAgdGhlbWVfdm9pZChiYXNlX3NpemUgPSA4LCBiYXNlX2ZhbWlseSA9ICJPcGVuIFNhbnMiKSArIAogICAgdGhlbWUoYXhpcy5saW5lLnggPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiZ3JleTQwIiksIAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3IgPSAiZ3JleTQwIiksIAogICAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9saW5lKGNvbG9yID0gImdyZXk0MCIpLCAKICAgICAgICAgIGF4aXMudGlja3MubGVuZ3RoLnggPSB1bml0KC40LCAibGluZXMiKSwgCiAgICAgICAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbigxMCwgNDUsIDEwLCAyMCkpCikgCmBgYAoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwfQpvbiArIGNvb3JkX2NhcnRlc2lhbihjbGlwID0gIm9mZiIpCmBgYAo=